package com.cz.ssyx.activity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cz.ssyx.activity.mapper.ActivityRuleMapper;
import com.cz.ssyx.activity.mapper.ActivitySkuMapper;
import com.cz.ssyx.activity.mapper.CouponInfoMapper;
import com.cz.ssyx.activity.service.CouponInfoService;
import com.cz.ssyx.client.product.ProductFeignClient;
import com.cz.ssyx.enums.ActivityType;
import com.cz.ssyx.model.activity.ActivityInfo;
import com.cz.ssyx.activity.mapper.ActivityInfoMapper;
import com.cz.ssyx.activity.service.ActivityInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cz.ssyx.model.activity.ActivityRule;
import com.cz.ssyx.model.activity.ActivitySku;
import com.cz.ssyx.model.activity.CouponInfo;
import com.cz.ssyx.model.order.CartInfo;
import com.cz.ssyx.model.product.SkuInfo;
import com.cz.ssyx.vo.activity.ActivityRuleVo;
import com.cz.ssyx.vo.order.CartInfoVo;
import com.cz.ssyx.vo.order.OrderConfirmVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 活动表 服务实现类
 * </p>
 *
 * @author Joker
 * @since 2024-04-20
 */
@Service
public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, ActivityInfo> implements ActivityInfoService {

    @Autowired
    private ActivityRuleMapper activityRuleMapper;

    @Autowired
    private ActivitySkuMapper activitySkuMapper;

    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private ProductFeignClient productFeignClient;


    //优惠活动列表方法
    @Override
    public IPage<ActivityInfo> selectPage(Page<ActivityInfo> pageParam) {

        IPage<ActivityInfo> page = baseMapper.selectPage(pageParam, null);
        page.getRecords().stream().forEach(item -> {
            item.setActivityTypeString(item.getActivityType().getComment());
        });
        return page;
    }

    //查询活动规则
    @Override
    public Map<String, Object> findActivityRuleList(Long id) {
        //创建一个map集合
        Map<String, Object> resultMap = new HashMap<>();

        //1.获取活动规则
        LambdaQueryWrapper<ActivityRule> activityRuleWrapper = new LambdaQueryWrapper<>();
        activityRuleWrapper.eq(ActivityRule::getActivityId, id);
        List<ActivityRule> activityRuleList = activityRuleMapper.selectList(activityRuleWrapper);

        //2.获取活动范围
        LambdaQueryWrapper<ActivitySku> activitySkuWrapper = new LambdaQueryWrapper<>();
        activitySkuWrapper.eq(ActivitySku::getActivityId, id);
        List<ActivitySku> activitySkuList = activitySkuMapper.selectList(activitySkuWrapper);

        List<SkuInfo> skuInfoList = null;

        if (!CollectionUtils.isEmpty(activitySkuList)) {
            //遍历活动范围列表，取出活动商品id的集合
            List<Long> skuIdList = activitySkuList.stream().map(ActivitySku::getSkuId).collect(Collectors.toList());
            //根据商品id远程调用service-product模块获取商品的详细信息

            skuInfoList = productFeignClient.findSkuInfoList(skuIdList);
        }

        //封装活动规则列表和活动商品列表
        resultMap.put("activityRuleList", activityRuleList);
        resultMap.put("skuInfoList", skuInfoList);

        return resultMap;
    }

    //保存活动规则
    @Override
    public void saveActivityRule(ActivityRuleVo activityRuleVo) {
        //先清除之前的活动规则和活动范围
        Long activityId = activityRuleVo.getActivityId();
        activityRuleMapper.delete(new LambdaQueryWrapper<ActivityRule>()
                .eq(ActivityRule::getActivityId, activityId));
        activitySkuMapper.delete(new LambdaQueryWrapper<ActivitySku>()
                .eq(ActivitySku::getActivityId, activityId));

        //存储规则列表
        List<ActivityRule> activityRuleList = activityRuleVo.getActivityRuleList();

        for (ActivityRule activityRule : activityRuleList) {
            activityRuleMapper.insert(activityRule);
        }

        //存储活动范围列表
        List<ActivitySku> activitySkuList = activityRuleVo.getActivitySkuList();

        for (ActivitySku activitySku : activitySkuList) {
            activitySku.setActivityId(activityId);
            activitySkuMapper.insert(activitySku);
        }

    }

    //根据关键词查询商品信息
    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
        //远程调用，获取全部的商品信息
        List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoByKeyword(keyword);

        if (skuInfoList.isEmpty()) {
            return skuInfoList;
        }

        //遍历出全部商品的id
        List<Long> skuIdList = skuInfoList.stream().map(SkuInfo::getId).collect(Collectors.toList());

        //编写sql语句，筛选出正在参加活动的商品
        List<Long> skuIdListExist = baseMapper.selectSkuIdListExist(skuIdList);

        //找出没在活动中的商品id
        ArrayList<SkuInfo> findSkuInfoList = new ArrayList<>();

        for (SkuInfo skuInfo : skuInfoList) {
            if (!skuIdListExist.contains(skuInfo.getId())) {
                findSkuInfoList.add(skuInfo);
            }
        }

        return findSkuInfoList;
    }

    //根据商品id集合查询出每个商品的活动规则信息
    @Override
    public Map<Long, List<String>> findActivity(List<Long> skuEsIdList) {
        //key为商品id，存放一个商品的一个或多个商品规则
        Map<Long, List<String>> map = new HashMap<>();

        //遍历skuId
        skuEsIdList.forEach(skuId -> {
            //通过skuId查询出商品的活动规则列表
            List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
            //封装数据
            if (!CollectionUtils.isEmpty(activityRuleList)) {
                List<String> ruleList = new ArrayList<>();
                HashSet<ActivityRule> activityRuleSet = new HashSet<>(activityRuleList);
                //通过调用方法，根据规则拼接出活动描述RuleDesc
                for (ActivityRule activityRule : activityRuleSet) {
                    ruleList.add(this.getRuleDesc(activityRule));
                }
                map.put(skuId, ruleList);
            }
        });
        return map;
    }

    //获取商品的活动信息和优惠券
    @Override
    public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {
        //1.返回参加的活动信息
        List<ActivityRule> activityRuleList = this.findActivityRuleListByUserId(skuId);

        //2.根据userId + skuId查询优惠券信息
        List<CouponInfo> couponInfoList = couponInfoService.findCouponInfoList(skuId, userId);

        //3.封装map集合，返回
        Map<String, Object> map = new HashMap<>();
        map.put("activityRuleList", activityRuleList);
        map.put("couponInfoList", couponInfoList);
        return map;
    }

    //获取带有优惠活动和优惠券的购物车信息
    @Override
    public OrderConfirmVo findCartActivityAndCoupon(List<CartInfo> cartInfoList, Long userId) {
        //1.把购物车里的每个商品都按照活动分组
        List<CartInfoVo> cartInfoVoList = this.findCartActivityList(cartInfoList);

        //2.计算参与活动后优惠（减少）的总金额
        BigDecimal activityReduceAmount = cartInfoVoList.stream().filter(cartInfoVo -> cartInfoVo.getActivityRule() != null) //过滤出活动不为空的商品
                .map(cartInfoVo -> cartInfoVo.getActivityRule().getReduceAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        //3.获取购物车内可用的优惠券列表
        List<CouponInfo> couponInfoList = couponInfoService.findCartCouponInfo(cartInfoList, userId);  //TODO

        //4.计算商品使用优惠券可以优惠的金额
        BigDecimal couponReduceAmount = new BigDecimal(0);
        if (!CollectionUtils.isEmpty(couponInfoList)) {
            couponReduceAmount = couponInfoList.stream()
                    .filter(couponInfo -> couponInfo.getIsOptimal() == 1)
                    .map(couponInfo -> couponInfo.getAmount())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        //5.计算如果没有参与活动，商品的总金额
        BigDecimal originalTotalAmount = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                .map(cartInfo -> cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        //6.最终金额
        BigDecimal totalAmount = originalTotalAmount.subtract(activityReduceAmount).subtract(couponReduceAmount);

        //返回最终对象
        OrderConfirmVo orderTradeVo = new OrderConfirmVo();
        orderTradeVo.setCarInfoVoList(cartInfoVoList);
        orderTradeVo.setActivityReduceAmount(activityReduceAmount);
        orderTradeVo.setCouponInfoList(couponInfoList);
        orderTradeVo.setCouponReduceAmount(couponReduceAmount);
        orderTradeVo.setOriginalTotalAmount(originalTotalAmount);
        orderTradeVo.setTotalAmount(totalAmount);
        return orderTradeVo;
    }

    //把购物车里的每个商品都按照活动分组
    public List<CartInfoVo> findCartActivityList(List<CartInfo> cartInfoList) {
        List<CartInfoVo> cartInfoVoList = new ArrayList<>();
        //1.获取所有的skuId
        List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).collect(Collectors.toList());

        //2.根据skuId查activity_sku 得到activityId
        List<ActivitySku> activitySkuList = baseMapper.selectCartActivity(skuIdList);
        ///根据活动id分组 属性为skuId
        Map<Long, Set<Long>> activityIdToSkuListMap = activitySkuList.stream().collect(
                Collectors.groupingBy(ActivitySku::getActivityId, //根据活动id分组
                        Collectors.mapping(ActivitySku::getSkuId, Collectors.toSet())  //属性为skuId，且为set，即skuId不能重复
                ));

        //3.再根据activityId 查出活动的规则信息
        ///key是activityId， values是活动的规则数据列表（一个活动可以有多个规则）
        Map<Long, List<ActivityRule>> activityIdToActivityRuleListMap = new HashMap<>();

        //先查出没有重复的活动id列表
        Set<Long> activityIdList = activitySkuList.stream().map(ActivitySku::getActivityId).collect(Collectors.toSet());

        //再根据活动id查出活动规则
        if (!CollectionUtils.isEmpty(activityIdList)) {
            //activity_rule表
            LambdaQueryWrapper<ActivityRule> wrapper = new LambdaQueryWrapper<>();
            wrapper.orderByDesc(ActivityRule::getConditionAmount, ActivityRule::getConditionNum);
            wrapper.in(ActivityRule::getActivityId, activityIdList);
            List<ActivityRule> activityRuleList = activityRuleMapper.selectList(wrapper);

            //封装到activityIdToActivityRuleListMap，根据活动id分组
            activityIdToActivityRuleListMap = activityRuleList.stream().collect(Collectors.groupingBy(ActivityRule::getActivityId));
        }

        //4.分类
        //4.1 有活动的商品
        Set<Long> activitySkuIdList = new HashSet<>();
        if (!CollectionUtils.isEmpty(activityIdToSkuListMap)) {
            //使用迭代器遍历
            Iterator<Map.Entry<Long, Set<Long>>> iterator = activityIdToSkuListMap.entrySet().iterator();
            Map.Entry<Long, Set<Long>> entry = iterator.next();
            //活动id
            Long activityId = entry.getKey();
            //每个活动对应的商品id列表
            Set<Long> currentActivitySkuIdSet = entry.getValue();

            //过滤出参加活动的商品购物项
            List<CartInfo> currentActivityCartInfoList = cartInfoList.stream().filter(cartInfo ->
                    currentActivitySkuIdSet.contains(cartInfo.getSkuId())
            ).collect(Collectors.toList());

            //计算参加活动的商品的总金额和总数量
            BigDecimal activityTotalAmount = this.computeTotalAmount(currentActivityCartInfoList);
            int activityTotalNum = this.computeCartNum(currentActivityCartInfoList);

            //根据activityId获取对应的规则
            List<ActivityRule> currentActivityRuleList = activityIdToActivityRuleListMap.get(activityId);
            ActivityType activityType = currentActivityRuleList.get(0).getActivityType();

            //判断活动类型
            ActivityRule activityRule = null;
            if (activityType == ActivityType.FULL_REDUCTION) {   //满减
                activityRule = this.computeFullReduction(activityTotalAmount, currentActivityRuleList);
            } else {  //满量
                activityRule = this.computeFullDiscount(activityTotalNum, activityTotalAmount, currentActivityRuleList);
            }

            //封装cartInfoVo
            CartInfoVo cartInfoVo = new CartInfoVo();
            cartInfoVo.setCartInfoList(currentActivityCartInfoList);
            cartInfoVo.setActivityRule(activityRule);
            cartInfoVoList.add(cartInfoVo);

            //记录哪些购物项参与了活动
            activitySkuIdList.addAll(currentActivitySkuIdSet);
        }

        //4.2 没有活动的商品
        skuIdList.removeAll(activitySkuIdList);
        if (!CollectionUtils.isEmpty(skuIdList)) {
            //skuId对应购物项
            Map<Long, CartInfo> skuIdCartInfoMap = cartInfoList.stream().collect(
                    Collectors.toMap(CartInfo::getSkuId, CartInfo -> CartInfo)
            );

            for (Long skuId : skuIdList) {
                CartInfoVo cartInfoVo = new CartInfoVo();
                cartInfoVo.setActivityRule(null);

                List<CartInfo> cartInfos = new ArrayList<>();
                cartInfos.add(skuIdCartInfoMap.get(skuId));

                cartInfoVo.setCartInfoList(cartInfos);
                cartInfoVoList.add(cartInfoVo);
            }
        }
        return cartInfoVoList;
    }

    private List<ActivityRule> findActivityRuleListByUserId(Long skuId) {
        List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
        for (ActivityRule activityRule : activityRuleList) {
            activityRule.setRuleDesc(this.getRuleDesc(activityRule));
        }
        return activityRuleList;
    }

    private List<ActivityRule> findActivityRuleListBySkuId(Long skuId) {
        // sku参与的活动信息Id
        List<Long> activityIdList = activitySkuMapper.selectList(new LambdaQueryWrapper<ActivitySku>().eq(ActivitySku::getSkuId, skuId)).stream().map(ActivitySku::getActivityId).collect(Collectors.toList());
        // 查活动规则
        List<ActivityRule> activityRuleList = activityRuleMapper.selectList(new LambdaQueryWrapper<ActivityRule>().in(ActivityRule::getActivityId, activityIdList));
//        List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
        
        for (ActivityRule activityRule : activityRuleList) {
            activityRule.setRuleDesc(this.getRuleDesc(activityRule));
        }
        return activityRuleList;
    }


    //构造规则名称的方法
    private String getRuleDesc(ActivityRule activityRule) {
        ActivityType activityType = activityRule.getActivityType();
        StringBuffer ruleDesc = new StringBuffer();
        if (activityType == ActivityType.FULL_REDUCTION) {
            ruleDesc
                    .append("满")
                    .append(activityRule.getConditionAmount())
                    .append("元减")
                    .append(activityRule.getBenefitAmount())
                    .append("元");
        } else {
            ruleDesc
                    .append("满")
                    .append(activityRule.getConditionNum())
                    .append("元打")
                    .append(activityRule.getBenefitDiscount())
                    .append("折");
        }
        return ruleDesc.toString();
    }

    /**
     * 计算满量打折最优规则
     *
     * @param totalNum
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠折扣从大到小排序了
     */
    private ActivityRule computeFullDiscount(Integer totalNum, BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项购买个数大于等于满减件数，则优化打折
            if (totalNum.intValue() >= activityRule.getConditionNum()) {
                BigDecimal skuDiscountTotalAmount = totalAmount.multiply(activityRule.getBenefitDiscount().divide(new BigDecimal("10")));
                BigDecimal reduceAmount = totalAmount.subtract(skuDiscountTotalAmount);
                activityRule.setReduceAmount(reduceAmount);
                optimalActivityRule = activityRule;
                break;
            }
        }
        if (null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size() - 1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionNum())
                    .append("元打")
                    .append(optimalActivityRule.getBenefitDiscount())
                    .append("折，还差")
                    .append(totalNum - optimalActivityRule.getConditionNum())
                    .append("件");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionNum())
                    .append("元打")
                    .append(optimalActivityRule.getBenefitDiscount())
                    .append("折，已减")
                    .append(optimalActivityRule.getReduceAmount())
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }

    /**
     * 计算满减最优规则
     *
     * @param totalAmount
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
     */
    private ActivityRule computeFullReduction(BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项金额大于等于满减金额，则优惠金额
            if (totalAmount.compareTo(activityRule.getConditionAmount()) > -1) {
                //优惠后减少金额
                activityRule.setReduceAmount(activityRule.getBenefitAmount());
                optimalActivityRule = activityRule;
                break;
            }
        }
        if (null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size() - 1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionAmount())
                    .append("元减")
                    .append(optimalActivityRule.getBenefitAmount())
                    .append("元，还差")
                    .append(totalAmount.subtract(optimalActivityRule.getConditionAmount()))
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionAmount())
                    .append("元减")
                    .append(optimalActivityRule.getBenefitAmount())
                    .append("元，已减")
                    .append(optimalActivityRule.getReduceAmount())
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }

    private BigDecimal computeTotalAmount(List<CartInfo> cartInfoList) {
        BigDecimal total = new BigDecimal("0");
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if (cartInfo.getIsChecked().intValue() == 1) {
                BigDecimal itemTotal = cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()));
                total = total.add(itemTotal);
            }
        }
        return total;
    }

    private int computeCartNum(List<CartInfo> cartInfoList) {
        int total = 0;
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if (cartInfo.getIsChecked().intValue() == 1) {
                total += cartInfo.getSkuNum();
            }
        }
        return total;
    }
}
